﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace WMH_Project
{
   public class SpecimenImpl : Specimen
    {
        public SpecimenImpl() { }
        public SpecimenImpl( Graph graph, Random random)
        {
            Debug.Assert(graph != null);
            Debug.Assert(random != null);

            numberOfX = graph.NumberOfX;
            numberOfY = graph.NumberOfY;
            this.graph = graph;
            edges = new Edge[graph.NumberOfX];
            cost = new int[graph.NumberOfY];

            this.random = random;

            for (int i = 0; i < graph.NumberOfX; i++)
                edges[i] = graph.NodesX[i].Edges[random.Next(graph.NodesX[i].NumberOfEdges)];

            randomArray = new int[numberOfY * 10];
            int index = 0;
            for (int i = 0; i < numberOfY; ++i)
                for (int j = 0; j < 10 * (((double)numberOfY - i + 1.0) / numberOfY); ++j)
                    randomArray[index++] = i;

            randomArrayMaxIndex = index;

        }
        public void Mutate(MutationParam probability)
        {
            if (probability.MutationType == MUTATION_TYPE.Normal)
            {
                for (int i = 0; i < numberOfX; ++i)
                    if (random.NextDouble() <= probability.Propa)
                    {
                        int numEdge = random.Next(graph.NodesX[i].NumberOfEdges);
                        Edge[i] = graph.NodesX[i].Edges[numEdge];
                    }
                return;
            }

            List<Tuple<double, int>> list = new List<Tuple<double, int>>();


            if (probability.MutationType == MUTATION_TYPE.Weighted)
            {
           
                for (int i = 0; i < numberOfX; ++i)
                    if (random.NextDouble() <= probability.Propa)
                    {
                        int numEdge = random.Next(randomArrayMaxIndex);
                        if (randomArray[numEdge] < graph.NodesX[i].NumberOfEdges)
                            Edge[i] = graph.NodesX[i].Edges[randomArray[numEdge]];
                        else
                        {
                            --i;
                            continue;
                        }
                    }
            }
        }
        private int calculateQuality()
        {
            int max = 0 ;
            for (int i = 0; i < numberOfY; i++)
                cost[i] = 0;
            for (int i = 0; i < numberOfX; i++) 
                cost[Edge[i].endID] += Edge[i].cost;
            for (int i = 0; i < numberOfY; i++)
                if (max < cost[i]) max = cost[i];
            return -max;
        }
        // Metoda zwraca string z informacją o osobniku w tym o jego genotypie
        public override string ToString()
        {
            string ret = "";
            for (int i = 0; i < numberOfX; i++)
                ret += i + ":" + Edge[i] + "\n";
            return ret;
        }
        public Specimen Crossover(Specimen specimen)
        {
            Debug.Assert(specimen!=null);
            SpecimenImpl specimenImpl = (SpecimenImpl) specimen;
            SpecimenImpl newSpecimen = new SpecimenImpl(graph,random);
            for (int i = 0; i < numberOfX; i++)
            {
                if(random.Next(2)==0)
                    newSpecimen.Edge[i] = edges[i];
                else
                    newSpecimen.Edge[i] = specimenImpl.Edge[i];
            }

            return newSpecimen;
        }

        public bool IsCorrect(Graph graph)
        {
            int i = 0;
            foreach (Edge it in edges)
            {

                if (it == null) throw new SystemException("Brak krawędzi w osobniku");
                if (!graph.NodesX[i].Edges.Contains(it))
                {
                    String msg;
                    msg = "Zwyrodniały osobnik. Wykroto osobnika który zawiera niepoprawne odwołania";
                    throw new SystemException(msg);
                }
                if (graph.NodesY[it.endID] == null) throw new SystemException("Węzeł o docelowym ID nie istnieje");
                i++;
            }
            return true;
        }


        private Edge[] edges;
        private int[] cost;
        private int numberOfX;
        private int numberOfY;
        private Graph graph;
        private int[] randomArray;
        private int randomArrayMaxIndex;

        private Random random;

        
        public int GetQuality()
        {
            if (!correctQuality)
                quality = calculateQuality();
            correctQuality = true;
            return quality;
        }

        private int quality;
        private bool correctQuality=false;
        

        public Edge[] Edge
        {
            get { return edges; }
            set { edges = value; }
        }
    }
}
